/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package syntaxanalyser;

import java.util.ArrayList;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Set;
import java.util.Stack;

/**
 *
 * @author mark_o
 */
public class Postfiks {
    protected ArrayList ex;
    protected Hashtable var;
    protected ArrayList function = new ArrayList();
    public static double eps = 0.00000011920928955078125;

    public int getVarCount(){
            return var.size();
    }
    public Hashtable Var(){
            return var;
    }
    protected int prior(String op)
    {
        if (op.equals("(") || op.equals(")")) return 0;
        if (op.equals("+") || op.equals("-")) return 1;
        if (op.equals("*") || op.equals("/") || op.equals("%")) return 2;
        if (op.equals("^")) return 3;
        if (op.equals("sin") || op.equals("cos") || op.equals("tg") ||
                op.equals("arctg") || op.equals("arcsin" ) || op.equals("arccos") ||
                op.equals("lg") || op.equals("log") || op.equals("exp") ) return 4;
        if (op.equals("u-")) return 5;
        return -1;
    }
    protected boolean  isop(String op)
    {
        if (op.equals("(") || op.equals(")") || op.equals("+") || op.equals("-") ||
                op.equals("*") || op.equals("/") || op.equals("%") || op.equals("^") ||
                op.equals("u-") || op.equals("sin") || op.equals("cos") || op.equals("tg") ||
                op.equals("arctg") || op.equals("arcsin" ) || op.equals("arccos") || op.equals("lg") ||
                op.equals("log") || op.equals("exp")) return true;
        return false;
    }
    protected boolean isdigit(char s)
    {
        if (s >= '0' && s <= '9') return true;
        return false;
    }
    public void input(String inp) throws Exception
    {
        ex = new ArrayList();
        var = new Hashtable();

        String temp = inp.replace(" ", "");
        String num = "";

        String prev = "";
        String func = "";
        for (int j = 0; j < temp.length(); j++)
        {
            if (isop( temp.charAt(j)+""))
            {
                if (((isop(prev) && !prev.equals(")") ) || prev.equals("") ) && (temp.charAt(j) == '-'))
                    ex.add("u-");
                else
                {
                    if (!num.equals(""))
                    {
                        ex.add(num);
                        num = "";
                    }
                    else
                        if (!isop(func) && !func.equals(""))
                        {
                            ex.add(func);
                            if (!func.equals("pi") && !func.equals("e") && !var.containsKey(func))
                                var.put(func, 0);
                            func = "";
                        }
                    if (temp.charAt(j) == '(' && isop(func))
                    {
                        ex.add(func);
                        func = "";
                    }
                    ex.add(temp.charAt(j));
                }
            }
            else
                if (isdigit(temp.charAt(j)))
                {
                    num += temp.charAt(j);
                    if (!func.equals("") && isop(func))
                    {
                        ex.add(func);
                        func = "";
                    }
                }
                else
                    if (temp.charAt(j) == ',' || temp.charAt(j) == '.')
                        num += ','; // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
                    else
                        if (temp.charAt(j) >= 'a' && temp.charAt(j) <= 'z')
                        {
                            if (isop(func) && !func.equals(""))
                            {
                                ex.add(func);
                                func = "";
                            }
                            func += temp.charAt(j);
                        }
                        else
                            throw new Exception("Некоректна функція");
            prev = temp.charAt(j)+"";

        }
        if (!num.equals("")) ex.add(num);
        else
            if (!func.equals("") && !isop(func))
            {
                ex.add(func);
                if (!func.equals("pi") && !func.equals("e")&& !var.containsKey(func))
                    var.put(func, 0);
            }
        for (int i = 0; i < ex.size(); i++)
            if (ex.get(i).toString().equals("pi"))
                ex.set(i, Math.PI);
            else
                if (ex.get(i).toString().equals("e"))
                    ex.set(i, Math.E);



        function.clear();
        for (int i = 0; i < ex.size(); i++){
            function.add(ex.get(i));
        }


    }
    public void set_var(ArrayList VarList)
    {

        ex.clear();
        for (int i = 0; i < function.size(); i++)
            ex.add(function.get(i));

        if (var.size() != 0)
        {

            int ind = 0;
            Hashtable new_var = new Hashtable();
            Set KeySet = var.keySet();
            for (Iterator key = KeySet.iterator(); key.hasNext();)
            {
                String s = VarList.get(ind++).toString();
                new_var.put(key.next(), (s.equals("pi")) ? Math.PI : ((s.equals("e")) ? Math.E : s));
            }
            var.clear();
            var = new_var;
            for (int i = 0; i < ex.size(); i++)
            {
                boolean ok = false;
                KeySet = var.keySet();
                for (Iterator key = KeySet.iterator(); key.hasNext();)
                {
                    if (key.next().toString().equals(ex.get(i).toString()))
                        ok = true;
                }
                if (ok)
                {
                    ex.set(i, var.get(ex.get(i)));
                }
            }
        }
        Stack<Object> st = new Stack<Object>();
        ArrayList res = new ArrayList();
        for(int index = 0;index<ex.size();index++)
        {
            Object o = ex.get(index);
            if (o == null) break;
            else
                if (o.toString().equals("(") )
                    st.push(o);
                else
                    if (o.toString().equals(")"))
                    {
                        while (true)
                        {
                            Object t = st.pop();
                            if (t.toString().equals("(")) break;
                            res.add(t);
                        }
                    }
                    else
                        if (isop(o.toString()))
                        {
                            while (true)
                            {
                                if (st.size() == 0) break;
                                Object t = st.pop();

                                if (isop(t.toString()))
                                    if (prior(t.toString()) < prior(o.toString()))
                                    { st.push(t); break; }
                                res.add(t);

                            }
                            st.push(o);
                        }
                        else
                            res.add(o);

        }
        while (st.size() != 0)
            res.add(st.pop());
        ex = res;

    }
    public void set_var()
    {
        /*if (var.size() != 0)
        {

        //Console.WriteLine();
        Hashtable new_var = new Hashtable();
        Set KeySet = var.keySet();
        for (Iterator Kkey = KeySet.iterator(); Kkey.hasNext();)
        {
        Object key = Kkey.next();
        System.out.write("{0} =  ", key);
        string s = Console.ReadLine();
        new_var.put(key, (s == "pi") ? Math.PI : ((s == "e") ? Math.E : s));
        }
        var.clear();
        var = new_var;
        Console.WriteLine();
        for (int i = 0; i < ex.size(); i++)
        {
        boolean ok = false;
        foreach (object key in var.GetKeyList())
        {
        if (key.toString() == ex[i].ToString())
        ok = true;
        }
        if (ok)
        {
        ex.set(i, var.get(ex.get(i)));
        }
        }
        }
        Stack<Object> st = new Stack<Object>();
        ArrayList res = new ArrayList();
        foreach (Object o in ex)
        {
        if (o == null) break;
        else
        if (o.toString() == "(")
        st.push(o);
        else
        if (o.toString() == ")")
        {
        while (true)
        {
        Object t = st.pop();
        if (t.toString() == "(") break;
        res.add(t);
        }
        }
        else
        if (isop(o.toString()))
        {
        while (true)
        {
        if (st.size() == 0) break;
        Object t = st.pop();

        if (isop(t.toString()))
        if (prior(t.toString()) < prior(o.toString()))
        { st.push(t); break; }
        res.add(t);

        }
        st.push(o);
        }
        else
        res.add(o);

        }
        while (st.size() != 0)
        res.add(st.pop());
        ex = res;*/
    }
    public double Valuete() throws Exception
    {
        Stack<Object> st = new Stack<Object>();
        //foreach (Object o in ex)
        for(int index = 0; index<ex.size();index++)
        {
            Object o = ex.get(index);
            if (o == null) break;
            if (!isop(o.toString()))
                st.push(o);
            if (o.toString().equals("(") || o.toString().equals(")"))
                throw new Exception("Некоректна функція");
            if (isop(o.toString()))
            {
                double x = 0;
                double y = 0;
                double result = 1;
                x = Double.parseDouble(st.pop().toString());
                if (o.toString().equals("u-"))
                    result = -x;
                else
                    if (o.toString().equals("sin"))
                        result = Math.sin(x);
                    else
                        if (o.toString().equals("cos"))
                            result = Math.cos(x);
                        else
                            if (o.toString().equals("tg"))
                                result = Math.tan(x);
                            else
                                if (o.toString().equals("lg"))
                                    result = Math.log10(x);
                                else
                                    if (o.toString().equals("exp"))
                                        result = Math.exp(x);
                                    else
                                        if (o.toString().equals("arcsin"))
                                            result = Math.asin(x);
                                        else
                                            if (o.toString().equals("arccos"))
                                                result = Math.acos(x);
                                            else
                                                if (o.toString().equals("arctg"))
                                                    result = Math.atan(x);
                                                else
                                                    if (o.toString().equals("log")
                                                    )
                                                        result = Math.log(x);
                                                    else
                                                    {
                                                        y = Double.parseDouble(st.pop().toString());
                                                        if (o.toString().equals("+"))
                                                            result = x + y;
                                                        if ((o.toString()).equals("-"))
                                                            result = y - x;
                                                        if ((o.toString()).equals("*"))
                                                            result = x * y;
                                                        if ((o.toString()).equals("/"))
                                                            result = y / x;
                                                        if ((o.toString()).equals("%"))
                                                            result = y % x;
                                                        if ((o.toString()).equals("^"))
                                                            result = Math.pow(y, x);
                                                    }
                st.push(result+"");
            }
        }
        return (Double.parseDouble(st.pop().toString()));
    }
}
